package com.bwie.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bwie.mapper.TbActiveRuleMapper;
import com.bwie.mapper.TbWinRecordMapper;
import com.bwie.pojo.TbActive;
import com.bwie.pojo.TbActiveRule;
import com.bwie.pojo.TbWinRecord;
import com.bwie.service.IUserService;
import com.bwie.service.TbActiveService;
import com.bwie.mapper.TbActiveMapper;
import com.bwie.utils.R;
import com.bwie.utils.TokenUtils;
import com.bwie.vo.PageInfoVo;
import io.jsonwebtoken.Jwts;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Lenovo
 * @description 针对表【tb_active(抽奖活动表)】的数据库操作Service实现
 * @createDate 2025-07-02 20:04:12
 */
@Service
public class TbActiveServiceImpl extends ServiceImpl<TbActiveMapper, TbActive>
        implements TbActiveService {

    @Autowired
    TbActiveMapper tbActiveMapper;
    @Autowired
    HttpServletRequest request;
    @Autowired
    TbActiveRuleMapper tbActiveRuleMapper;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    TbWinRecordMapper tbWinRecordMapper;
    @Autowired
    IUserService iUserService;
    @Autowired
    RedissonClient redissonClient;
    @Autowired
    KafkaTemplate kafkaTemplate;

    @Override
    public R getActiveList(PageInfoVo pageInfoVo) {
        Page<TbActive> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

        Page<TbActive> tbActivePage = tbActiveMapper.getActiveList(page, pageInfoVo);

        return R.ok(tbActivePage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addActive(TbActive tbActive) {
        String token = request.getHeader("token");
        if (token == null) {
            return R.error(404, "请先登录");
        }

        //处理开始时间和截止时间
        try {
            List<String> activeTime = tbActive.getActiveTime();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            tbActive.setBeginTime(format.parse(activeTime.get(0)));
            tbActive.setEndTime(format.parse(activeTime.get(1)));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        //审计字段
        String userName = TokenUtils.getUserName(token);
        tbActive.setCreateBy(userName);
        tbActive.setCreateTime(new Date());

        tbActiveMapper.insert(tbActive);

        for (TbActiveRule tbActiveRule : tbActive.getRuleList()) {
            tbActiveRule.setActiveId(tbActive.getActiveId());

            //审计字段
            tbActiveRule.setCreateBy(userName);
            tbActiveRule.setCreateTime(new Date());

            tbActiveRuleMapper.insert(tbActiveRule);
        }
        return R.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R joinActive(Integer activeId) {
        //获取用户ID
        String token = request.getHeader("token");
        if (token == null) {
            return R.error(404, "请先登录");
        }
        Integer userId = TokenUtils.getUserId(token);
        String userName = TokenUtils.getUserName(token);

        //获取活动信息
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if (tbActive == null) {
            return R.error(404, "活动不存在");
        }

        //根据状态
        if (tbActive.getActiveStatus() != 0) {
            return R.error(500, "活动已经结束了，谢谢您的参与！！！");
        }
        //根据时间判断
        long now = System.currentTimeMillis();
        if (now < tbActive.getBeginTime().getTime()) {
            return R.error(500, "活动未开始，请等待...");
        }
        if (now > tbActive.getEndTime().getTime()) {
            return R.error(500, "活动已经结束了，谢谢你的参与！！！");
        }

        //检查用户是否有资格抽奖
        String joinKey = "join-" + activeId + "-" + userId;
        Boolean hasJoinKey = stringRedisTemplate.hasKey(joinKey);
        if (!hasJoinKey) {
            //说明从来没有参与过
            stringRedisTemplate.opsForValue().set(joinKey, "" + tbActive.getFreeTimes());
        } else {
            //说明用户参与过
        }
        Long times = stringRedisTemplate.opsForValue().decrement(joinKey);
        if (times < 0) {
            return R.error(500, "您已经没有抽奖次数了，请勿重复参与");
        }

        //redis - 活动
        String activeKey = "active-" + activeId;
        Boolean hasKey = stringRedisTemplate.hasKey(activeKey);
        if (!hasKey) {
            //活动数据还未加载，加载活动数据
            List<TbActiveRule> tbActiveRules = tbActiveRuleMapper.selectList(
                    new LambdaQueryWrapper<TbActiveRule>().eq(TbActiveRule::getActiveId, activeId)
            );

            //把活动规则放入缓存
            ArrayList<String> list = new ArrayList<>();
            for (TbActiveRule tbActiveRule : tbActiveRules) {
                list.add(tbActiveRule.getRuleId() + "");
            }

            //填充100个规则，如果ID为0，表示没有中奖，如果ID不为0，表示中奖
            while (list.size() < 100) {
                list.add("0");
            }

            //打乱顺序
            Collections.shuffle(list);

            //把打乱顺序后的数据，放入redis的list中
            stringRedisTemplate.opsForList().leftPushAll(activeKey, list);
        }

        //抽奖
        String s = stringRedisTemplate.opsForList().rightPop(activeKey);
        if (s == null) {
            tbActive.setActiveStatus(1);
            tbActive.setUpdateBy(userName);
            tbActive.setUpdateTime(new Date());
            return R.error(404, "奖品已抽光，谢谢参与！！！");
        }
        TbWinRecord tbWinRecord = new TbWinRecord();
        if (s.equals("0")) {

            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(0);
            tbWinRecord.setRecordDesc("未中奖");
            tbWinRecord.setActiveType(tbActive.getWinType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(userName);
            tbWinRecord.setCreateTime(new Date());
        } else {
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(Integer.valueOf(s));
            tbWinRecord.setRecordDesc("中奖了");
            tbWinRecord.setActiveType(tbActive.getWinType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(userName);
            tbWinRecord.setCreateTime(new Date());
        }

        tbWinRecordMapper.insert(tbWinRecord);
        return R.ok();
    }

    private R doJoinActiveByScore(Integer activeId){
        //获取用户ID
        String token = request.getHeader("token");
        if (token == null) {
            return R.error(404, "请先登录");
        }
        Integer userId = TokenUtils.getUserId(token);
        String userName = TokenUtils.getUserName(token);

        //获取活动信息
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if (tbActive == null) {
            return R.error(404, "活动不存在");
        }

        //根据状态
        if (tbActive.getActiveStatus() != 0) {
            return R.error(500, "活动已经结束了，谢谢您的参与！！！");
        }
        //根据时间判断
        long now = System.currentTimeMillis();
        if (now < tbActive.getBeginTime().getTime()) {
            return R.error(500, "活动未开始，请等待...");
        }
        if (now > tbActive.getEndTime().getTime()) {
            return R.error(500, "活动已经结束了，谢谢你的参与！！！");
        }

        //检查用户是否有资格抽奖
        String joinKey = "join-" + activeId + "-" + userId;
        Boolean hasJoinKey = stringRedisTemplate.hasKey(joinKey);
        if (!hasJoinKey) {
            //说明从来没有参与过
            stringRedisTemplate.opsForValue().set(joinKey, "" + tbActive.getFreeTimes());
        } else {
            //说明用户参与过
        }

        //抽奖扣减积分
        Integer payScore = tbActive.getPayScore();
        //扣减用户积分
        //积分不足，不能参与抽奖
        R r = iUserService.joinActiveSubScore(userId, payScore);
        if (r.getCode() != 200) {
            return r;
        }

        //redis - 活动
        String activeKey = "active-" + activeId;
        Boolean hasKey = stringRedisTemplate.hasKey(activeKey);
        if (!hasKey) {
            //活动数据还未加载，加载活动数据
            List<TbActiveRule> tbActiveRules = tbActiveRuleMapper.selectList(
                    new LambdaQueryWrapper<TbActiveRule>().eq(TbActiveRule::getActiveId, activeId)
            );

            //把活动规则放入缓存
            ArrayList<String> list = new ArrayList<>();
            for (TbActiveRule tbActiveRule : tbActiveRules) {
                list.add(tbActiveRule.getRuleId() + "");
            }

            //填充100个规则，如果ID为0，表示没有中奖，如果ID不为0，表示中奖
            while (list.size() < 100) {
                list.add("0");
            }

            //打乱顺序
            Collections.shuffle(list);

            //把打乱顺序后的数据，放入redis的list中
            stringRedisTemplate.opsForList().leftPushAll(activeKey, list);
        }

        //抽奖
        String s = stringRedisTemplate.opsForList().rightPop(activeKey);
        if (s == null) {
            tbActive.setActiveStatus(1);
            tbActive.setUpdateBy(userName);
            tbActive.setUpdateTime(new Date());
            return R.error(404, "奖品已抽光，谢谢参与！！！");
        }
        TbWinRecord tbWinRecord = new TbWinRecord();
        if (s.equals("0")) {
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(0);
            tbWinRecord.setRecordDesc("未中奖");
            tbWinRecord.setActiveType(tbActive.getWinType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(userName);
            tbWinRecord.setCreateTime(new Date());
            tbWinRecordMapper.insert(tbWinRecord);

            return R.error(500, "感谢您的参与，您并未中奖");
        } else {
            //中奖，使用mq记录
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(Integer.valueOf(s));
            tbWinRecord.setRecordDesc("中奖了");
            tbWinRecord.setActiveType(tbActive.getWinType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(userName);
            tbWinRecord.setCreateTime(new Date());

            //发送kafka消息
            kafkaTemplate.send("topic-record", JSON.toJSONString(tbWinRecord));


            TbActiveRule tbActiveRule = tbActiveRuleMapper.selectById(tbWinRecord.getRuleId());
            return R.ok("恭喜您中奖了，您抽中了" + tbActiveRule.getRuleName());
        }
    }

    @KafkaListener(topics = "topic-record")
    public void recvRecordMessage(String msg, Acknowledgment acknowledgment){
        //接受并转换消息
        System.out.println("kafka接收到的消息："+msg);
        TbWinRecord tbWinRecord = JSON.parseObject(msg, TbWinRecord.class);
        //保存中奖记录
        tbWinRecordMapper.insert(tbWinRecord);

        acknowledgment.acknowledge();
    }

    @Override
    public R joinActiveByScore(Integer activeId) {
        //获取分布式锁
        String lockKey = "activeId-" + activeId;
        RLock rLock = redissonClient.getLock(lockKey);
        try {
            //加锁
            rLock.lock();
            //积分抽奖
            return doJoinActiveByScore(activeId);
        } finally {
            //解锁一定要在finally中
            rLock.unlock();
        }
    }

    @Override
    public R getJoinRecord(PageInfoVo pageInfoVo) {
        Page<TbWinRecord> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

//        LambdaQueryWrapper<TbWinRecord> wrapper = new LambdaQueryWrapper<>();
//        wrapper.eq(TbWinRecord::getActiveId,pageInfoVo.getTypeId());
//        wrapper.orderByDesc(TbWinRecord::getCreateTime);

        Page<TbWinRecord> tbWinRecordPage = tbWinRecordMapper.getJoinRecord(page, pageInfoVo);
        return R.ok(tbWinRecordPage);
    }

    @Override
    public R getActiveById(Integer activeId) {
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if(tbActive == null){
            return R.error(404,"活动不存在");
        }

        //返回信息
        return R.ok(tbActive);
    }
}




